AnsibleとServerspecでcronについてちょっとハマった話
大栗です。
最近こんなブログが書かれたことで
と煽られているので、泣きながらAnsibleのテストをServerspecで書いています。cron設定をAnsibleで書いてServerspecでテストする時に少しハマったので紹介します。
やりたい事
普通にcronの設定をAnsibleで記述してServerspecでcronの内容のテストをする、と単純なことです。
ちなみに『kitchen-ansiblepushを利用したAnsible roleのテスト環境構築』を参考にTest Kitchenの環境を作りました。
ハマった事
まず普通にAnsibleでcronの設定を書いてみます。こんな感じでcronのタスクを書きました。
- name: cron setting cron: name: cron setting minute: "*/5" user: ec2-user job: "ls -al ~/ | logger -t cron-set -p local0.info" cron_file: cron-set
そして、Serverspecでは『Ansibleのテストで使いたい8つのServerspec』を参考に書いてみました。
describe cron do it { should have_entry('*/5 * * * * ls -al ~/ | logger -t cron-set -p local0.info').with_user('ec2-user') } end
Serverspecを実行すると、failしてしまいます。。。
Cron should have entry "*/5 * * * * ls -al ~/ | logger -t cron-set -p local0.info" (FAILED - 1) Failures: 1) Cron should have entry "*/5 * * * * ls -al ~/ | logger -t cron-set -p local0.info" On host `54.250.174.181' Failure/Error: it { should have_entry('*/5 * * * * ls -al ~/ | logger -t cron-set -p local0.info').with_user('ec2-user') } expected Cron to have entry "*/5 * * * * ls -al ~/ | logger -t cron-set -p local0.info" sudo -p 'Password: ' /bin/sh -c crontab\ -u\ ec2-user\ -l\ \|\ grep\ -v\ \'\^\[\[:space:\]\]\*\#\'\ \|\ grep\ --\ \^\\\\\\\*/5\\\ \\\\\\\*\\\ \\\\\\\*\\\ \\\\\\\*\\\ \\\\\\\*\\\ ls\\\ -al\\\ \\\~/\\\ \\\|\\\ logger\\\ -t\\\ cron-set\\\ -p\\\ local0.info\$ # ./spec/cron-setting/cron-setting_spec.rb:4:in `block (2 levels) in <top (required)>' Finished in 2.51 seconds (files took 1.21 seconds to load) 1 example, 1 failure
原因は?
原因はAnsibleでcron_file
を設定していることが原因でした。
Ansibleではcron_file
を設定しないと/var/spool/cron/<ユーザ名>
にcronを記述するのですが、cron_file
を設定すると/etc/cron.d/<cron_fileの値>
にcron設定を記述します。一方Serverspecのcronではcrontabの内容を取得するようです。つまり/var/spool/cron/<ユーザ名>
の内容です。今回Ansibleでcron_file
を設定していたのでcron設定の場所が異なりテストでfailしたという事でした。
解決策
一番簡単な解決策はAnsibleでcron_file
を設定しないことです。
- name: cron setting cron: name: cron setting minute: "*/5" user: ec2-user job: "ls -al ~/ | logger -t cron-set -p local0.info"
すると、こんな感じにパスします。
Cron should have entry "*/5 * * * * ls -al ~/ | logger -t cron-set -p local0.info" Finished in 0.46809 seconds (files took 2.06 seconds to load) 1 example, 0 failures
どうしても/etc/cron.d/<cron_fileの値>
に記述したいという場合はServerspec側でテストの記述を変える必要があります。この場合はfile
で中身を確認します。match
では正規表現リテラルを記述するのですが、固定の文字列が含まれているかを確認したいだけなのでRegexp.escape
とRegexp.compile
でこんな感じに書いてみました。
describe file('/etc/cron.d/cron-set') do its(:content) { should match Regexp.compile(Regexp.escape('*/5 * * * * ec2-user ls -al ~/ | logger -t cron-set -p local0.info')) } end
こんな感じにテストをパスします。
File "/etc/cron.d/cron-set" content should match /\*\/5\ \*\ \*\ \*\ \*\ ec2\-user\ ls\ \-al\ ~\/\ \|\ logger\ \-t\ cron\-set\ \-p\ local0\.info/ Finished in 1.89 seconds (files took 1.45 seconds to load) 1 example, 0 failures
さいごに
ちゃんとドキュメントを読め!と怒られる内容でした。Serverspecではcron
のResource Typeで/etc/cron.d/
以下の内容を見ない模様なのでAnsibleのcronとServerspecのcronでは微妙に仕様は異なると言うことです。
何はともあれ『さばんなちほーでも「Ansible Roleのテスト書いてるぜ」と言えるよう』なって良かったです。